#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stdint.h"
#include <dirent.h>
#include <sys/stat.h>
#include "stdint.h"
#include "ctype.h"

#define WAV_HEADER_LEN 44
#define MAX_FILES 100

typedef struct {
    uint32_t size;  //文件大小
    char name[256]; //文件名称
} FileInfo;

typedef struct {
    uint32_t size;
    FileInfo FileInfos[MAX_FILES];
} FileInfo_flag_t;

FileInfo_flag_t FileInfo_flag_input;
FileInfo_flag_t FileInfo_flag_bin;
FileInfo_flag_t FileInfo_flag_output;

// 不区分大小写的扩展名检查函数
int isBinFile(const char *filename) {
    // 获取文件扩展名
    const char *dot = strrchr(filename, '.');
    if (!dot || dot == filename) {
        return 0;  // 没有扩展名或只有扩展名的文件
    }
    // 跳过点号并检查扩展名是否匹配
    const char *ext = dot + 1;
    if (strcasecmp(ext, "bin") == 0) {
        return 1;
    }
    return 0;
}

// 比较函数：用于文件名排序 (升序)
int compareFiles(const struct dirent **a, const struct dirent **b) {
    return strcoll((*a)->d_name, (*b)->d_name);
}

// Linux/macOS实现
void traverseDir(const char *base_path, int depth, uint8_t mode) {
    static uint32_t count = 0;
    struct dirent **file_list;
    int file_count;
    char path[1024];

    // 获取排序后的文件列表 (包括文件夹)
    file_count = scandir(base_path, &file_list, NULL, compareFiles);

    // 遍历所有文件/目录
    for (int i = 0; i < file_count; i++) {
        struct stat stat_buf;
        const char *name = file_list[i]->d_name;
        
        // 忽略当前目录(.)和父目录(..)
        if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
            free(file_list[i]);
            continue;
        }

        // 构建完整路径
        snprintf(path, sizeof(path), "%s/%s", base_path, name);

        // 获取文件信息
        if (lstat(path, &stat_buf) < 0) {
            perror("lstat");
            free(file_list[i]);
            continue;
        }

        // 打印文件信息
        if (S_ISDIR(stat_buf.st_mode)) {
            traverseDir(path, depth + 1, mode); // 递归进入子目录
        } else {
            if (mode == 1) {
                if (isBinFile(name) == 1) {
                    FileInfo_flag_bin.FileInfos[FileInfo_flag_bin.size].size = stat_buf.st_size;
                    memcpy(FileInfo_flag_bin.FileInfos[FileInfo_flag_bin.size].name, path, strlen(path));
                    FileInfo_flag_bin.size++;
                }
            }
            else
            {
                FileInfo_flag_input.FileInfos[FileInfo_flag_input.size].size = stat_buf.st_size;
                memcpy(FileInfo_flag_input.FileInfos[FileInfo_flag_input.size].name, path, strlen(path));
                FileInfo_flag_input.size++;
            }
        }
        free(file_list[i]);
    }
    free(file_list);
}

// BMP文件处理函数
void fileNameChange(const char *oldpath, char *newpath) {
    // 检查是否是BMP文件（不区分大小写）
    const char *ext = strrchr(oldpath, '.');
    if (!ext) return;
    
    // 转换为小写比较
    char ext_lower[6] = {0};
    for (int i = 0; ext[i] && i < sizeof(ext_lower)-1; i++) {
        ext_lower[i] = tolower(ext[i+1]); // 跳过点号
    }
    
    // 判断是否为bmp后缀
    if (strcmp(ext_lower, "wav") == 0) {
        // 构建新文件名（替换后缀为.bin）
        strcpy(newpath, oldpath);
        char *new_ext = strrchr(newpath, '.');
        
        if (new_ext) {
            strcpy(new_ext + 1, "bin");
        }
    }
}


int main(int argc, char *argv[]) {

    if (argc < 2) {
        fprintf(stderr, "用法: %s <输入文件夹>\n", argv[0]);
        return 1;
    }

    //遍历文件夹文件
    FileInfo_flag_input.size = 0;
    traverseDir(argv[1], 0, 0);

    for (uint32_t i = 0; i < FileInfo_flag_input.size; i++) {
        fileNameChange(FileInfo_flag_input.FileInfos[i].name, FileInfo_flag_output.FileInfos[i].name);
        if (strlen(FileInfo_flag_output.FileInfos[i].name) > 0) {
            // 打开WAV文件
            FILE *wavFile = fopen(FileInfo_flag_input.FileInfos[i].name, "rb");
            if (!wavFile) {
                perror("❌ 无法打开输入文件");
                return 1;
            }

            // 获取文件大小
            fseek(wavFile, 0, SEEK_END);
            long fileSize = ftell(wavFile);
            fseek(wavFile, 0, SEEK_SET);
            FileInfo_flag_input.FileInfos[i].size = fileSize;

            uint32_t dataSize = fileSize - WAV_HEADER_LEN;
            uint32_t writeDataSize = dataSize + ((dataSize % 16) ? (16 - (dataSize % 16)) : 0);

            FileInfo_flag_output.FileInfos[i].size = writeDataSize;
        
            // 定位并读取WAV数据
            fseek(wavFile, WAV_HEADER_LEN, SEEK_SET);
            unsigned char *wavData = malloc(writeDataSize);
            if (!wavData) {
                printf("⚠️ 内存分配失败\n");
                fclose(wavFile);
                return 1;
            }

            if (fread(wavData, 1, dataSize, wavFile) != dataSize) {
                printf("⚠️ 数据读取失败\n");
                free(wavData);
                fclose(wavFile);
                return 1;
            }
            fclose(wavFile);

            // 交换相邻字节的高低位
            for (long i = 0; i < dataSize - 1; i += 2) {
                unsigned char temp = wavData[i];
                wavData[i] = wavData[i + 1];
                wavData[i + 1] = temp;
            }
            memset(&wavData[dataSize], 0, writeDataSize - dataSize);
            // 打开BIN文件
            FILE *binFile = fopen(FileInfo_flag_output.FileInfos[i].name, "wb");
            if (!binFile) {
                perror("Error creating BIN file");
                free(wavData);
                return EXIT_FAILURE;
            }
            // 写入BIN文件
            size_t bytes_written = fwrite(wavData, 1, writeDataSize, binFile);
            if (bytes_written != writeDataSize) {
                perror("Error writing to BIN file");
            }
            free(wavData);
            fclose(binFile);
            printf("wav size %d bin size %d\n", FileInfo_flag_input.FileInfos[i].size, FileInfo_flag_output.FileInfos[i].size);
            printf("Output file: %s (%ld bytes)\n", FileInfo_flag_output.FileInfos[i].name, bytes_written);
        } else {
            continue;
        }
    }

    //合并bin文件
    FileInfo_flag_bin.size = 0;
    traverseDir(argv[1], 0, 1);

    uint32_t totalSize = 0;
    for (uint32_t i = 0; i < FileInfo_flag_bin.size; i++) {
        totalSize += FileInfo_flag_bin.FileInfos[i].size;
        printf("文件 %03d: %s (大小: %u bytes)\n", i + 1, FileInfo_flag_bin.FileInfos[i].name, FileInfo_flag_bin.FileInfos[i].size);
    }

    totalSize += 32;
    printf("总大小: %u bytes\n", totalSize);

    unsigned char *binData = malloc(totalSize);
    if (!binData) {
        printf("⚠️ 内存分配失败\n");
        return 1;
    }
    
    FILE *outTxt = fopen("output.txt", "w");
    if (!outTxt) {
        printf("⚠️ 无法创建输出文件\n");
        return 1;
    }
    fprintf(outTxt, "total size:%d\n    ", totalSize);

    FILE *outBin = fopen("output.bin", "wb");
    if (!outBin) {
        printf("⚠️ 无法创建输出文件\n");
        free(binData);
        return 1;
    }
    uint32_t offset = 0;
    offset += 32;
    memset(binData, 0, 32);
    // 前两字节修改，应该是版本号相关东西
    binData[0] = 0x38;
    binData[1] = 0x01;

    for (uint32_t i = 0; i < FileInfo_flag_bin.size; i++) {
        unsigned char *singleBinData = malloc(FileInfo_flag_bin.FileInfos[i].size);
        if (!singleBinData) {
            printf("⚠️ 内存分配失败\n");
            return 1;
        }
        FILE *rdBin = fopen(FileInfo_flag_bin.FileInfos[i].name, "rb");
        if (fread(singleBinData, 1, FileInfo_flag_bin.FileInfos[i].size, rdBin) != FileInfo_flag_bin.FileInfos[i].size) {
            printf("⚠️ 数据读取失败\n");
            free(singleBinData);
            fclose(rdBin);
            return 1;
        }
        fprintf(outTxt, "%s size:0x%08x  offset 0x%08x\n    ", FileInfo_flag_bin.FileInfos[i].name,  FileInfo_flag_bin.FileInfos[i].size, offset);
        memcpy(&binData[offset], singleBinData, FileInfo_flag_bin.FileInfos[i].size);
        offset += FileInfo_flag_bin.FileInfos[i].size;
        free(singleBinData);
        fclose(rdBin);
    }

    fwrite(binData, 1, totalSize, outBin);
    fclose(outBin);
    free(binData);
    fclose(outTxt);

    printf("All BIN files merged into output.bin successfully!\n");

    return 0;
}